import RenderContext  from "@/views/cg/lib/RenderContextGame.ts";
import {Model} from "@/views/cg/lib";
import Redo from "wangeditor/dist/menus/redo";
import {Mat4} from "@/views/cg/lib/matrix";

export default class GameField extends Model{
  constructor(game) {
    const map = [
      "....................................................",
      "....................................................",
      "....................................................",
      "....................................................",
      "....................................................",
      "....................................................",
      "....................................................",
      "....................................................",
      "....................................................",
      "....................................................",
      "....................................................",
      "....................................................",
      "....................................................",
      "....................................................",
      "....................................................",
      "....................................................",
      "....................................................",
      "....................................................",
      "....................................................",
      "....................................................",
      "....................................................",
      "....................................................",
      "....................................................",
      "....................................................",
      "....................................................",
      "....................................................",
      "....................................................",
      "....................................................",
      "....................................................",
      "....................................................",
      "....................................................",
      "....................................................",
    ]
    super(null);
    this.width = map[0].length;
    this.height = map.height;
    this.tileSize = 0.5;
    this.tileModel = new Tiles(map, this.tileSize);
    this.game = game;
    this.addChild(this.tileModel);

    //
    // x -> [0,10] -> [0,5] -> [-2.5,2.5]

    this.addTextureImage('/texture03.jpg');
    // 存储所有的单位
    this.units = [];
    // 初始化选择
    this.initPick();
    const aspect = RenderContext.getAspect();
    this.lookAtParams = [0,1,2, -Math.PI*0.33, 0,0];
    this.fov = Math.PI * 0.6;
    this.near = 1;
    this.far = 2000;

  }

  draw(){
    const gl = this.gl;
    RenderContext.switchProgram('default');
    gl.bindFramebuffer(gl.FRAMEBUFFER, null)
    gl.enable(gl.DEPTH_TEST)
    gl.depthFunc(gl.LEQUAL)
    gl.clearDepth(1.0)
    gl.viewport(0.0, 0.0, canvas.width, canvas.height);
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
    // 支持选择
    this.setFloatUniform('u_id', this.currentUid)

    this.setMatrixUniform('u_worldview', this.projectViewMatrix)
    this.updateMatrix();
    this.disableAttribute('a_color')
    this.disableAttribute('a_norm')
    super.draw()

    // 判断的是 http://localhost:3000/19-pick 这个地址
    if(!window.location.href.match(/(17|18)/)){
      RenderContext.switchProgram('pick');
      this.enableAttribute('a_color');
      this.disableAttribute('a_texcoord');
      this.disableAttribute('a_id');
      this.pick();
      this.enableAttribute('a_id');
      this.enableAttribute('a_texcoord');
    }
  }

  initPick(){
    const gl = this.gl;
    // 构造一个纹理对象
    const targetTexture = gl.createTexture();
    // 并设置纹理对象得属性
    gl.bindTexture(gl.TEXTURE_2D, targetTexture);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S,gl.CLAMP_TO_EDGE);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T,gl.CLAMP_TO_EDGE);

    // webgl-fundamentals 这本书中拿过来的
    function setFramebufferAttachmentSizes(width, height){
      // 给这个纹理对象 添加上空数据
      gl.bindTexture(gl.TEXTURE_2D, targetTexture)
      // define size and format of level 0
      const level = 0;
      const internalFormat = gl.RGBA;
      const border = 0;
      const format = gl.RGBA;
      const type= gl.UNSIGNED_BYTE;
      const data = null;
      gl.texImage2D(
        gl.TEXTURE_2D,
        level,
        internalFormat,
        width,
        height,
        border,
        format,
        type,
        data
      )
    }

    setFramebufferAttachmentSizes(1,1);
    // create and bind the formatBuffer 创造frameBuffer
    const fb = gl.createFramebuffer();
    gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
    // 如果想要取消往这个buffer上绘制
    // gl.bindFramebuffer(gl.FRAMEBUFFER, null);
    this.fb = fb;

    // attach the texture as the first color attachment
    const attachmentPoint = gl.COLOR_ATTACHMENT0;
    const level = 0;
    // 我要把这个buffer画出来给一个纹理对象， 纹理对象和framebuffer关联起来
    gl.framebufferTexture2D(
      gl.FRAMEBUFFER,
      attachmentPoint,
      gl.TEXTURE_2D,
      targetTexture,
      level
    );

    this.gl.canvas.addEventListener('click',(e) => {
      if(document.pointerLockElement){
        this.game.emitter.emit('action',{
          type:e.button == 0?'move':'attack',
          position: [ this.selX, this.selY]
        });
      }
    })

    document.addEventListener('mousemove',(e) => {
      const rect = gl.canvas.getBoundingClientRect();
      if(!this.mouseX){
        this.mouseX = e.clientX - rect.left
        this.mouseY = e.clientY - rect.top
      }
      this.mouseX += e.movementX;
      this.mouseY += e.movementY;
    },false)
  }

  pick(){
    const gl = this.gl;
    if(!this.mouseX){
      return;
    }
    RenderContext.switchProgram('pick');
    gl.bindFramebuffer(gl.FRAMEBUFFER, this.fb)
    const pixelX = (this.mouseX * gl.canvas.width) / gl.canvas.height;
    const pixelY =
      gl.canvas.height - (this.mouseY * gl.canvas.height)/gl.canvas.clientHeight -
      1;

    // 计算near平面的值
    const aspect = RenderContext.getAspect()
    const top = Math.tan(this.fov * 0.5) * this.near;
    const button = -top;
    const left = aspect * button;
    const right =aspect * top;
    const width = Math.abs(right - left);
    const height = Math.abs(top - buttom);

    // 将鼠标坐标映射到near平面
    const fLeft = left +(pixelX * width) / this.gl.canvas.width;
    const fBottom = bottom + (pixelY*height) / this.gl.canvas.height;
    const fWidth = 1/gl.canvas.width;
    const fHieght = 1/gl.canvas.height;

    this.setMatrixUniform(
      'u_worldview',
      new Mat4()
        .lookAt(...this.lookAtParams)
        .frustum(fLeft, fLeft+fWidth, fBottom, fBottom+fHieght)
        .getMatrix(),
      RenderContext.getProgram()
    )

    gl.viewport(0,0,1,1);
    // gl.enable(gl.CULL_FACE);
    gl.enable(gl.DEPTH_TEST)

    //Clear the canvas AND the depth buffer.
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
    this.children[0].draw();

    const data = new Unit8Array(4);
    gl.readPixels(0,0,1,1,gl.RGBA, gl.UNSIGNED_BYTE, data);
    const id = data[0] + (data[1] << 8) + (data[2] << 16)
    const y = id % 1000
    const x = Math.floor(id/1000)
    // this.setFloatUniform(‘u_id’,id)
    this.selX = x;
    this.selY = y;
    this.currentUid = id;
    gl.bindFramebuffer(gl.FRAMEBUFFER, null);
  }
}
